import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

/**
* Class Mosca
*
* Questa classe permette di disegnare una mosca e di farla muovere sul piano
*
* @author Simoncelli Davide && Beschi Jacopo
*
*/
/* 
 * COLORI E CAZZATINE
 */
public class Mosca implements Runnable {
       
       /**
        * Coordinata x della mosca
        */
       
       private int xA;
       
       /**
        * Coordinata y della mosca
        */
       
       private int yA;
       
       /**
        * Posizione lungo la coordinata x del sistema e quindi della mosca
        */
       
       private double xPos ;
       
       /**
        * Posizione lungo la coordinata x del sistema e quindi della mosca
        */
       
       private double yPos;
       
       /**
        * Coordinata x che la mosca deve raggiungere
        */
       
       private int xDaRaggiungere;
       
       /**
        * Coordinata y che la mosca deve raggiungere
        */
       
       private int yDaRaggiungere;
       
       /**
        * Oggetto AffineTransform per poter translaere il sistema
        */
       
       private AffineTransform trasf;
       
       /**
        * Oggetto Primo sul quale disegnare
        */
       
       private Primo p;

       /**
        * Thread principale delal classe
        */
       
       private Thread t;
       
       /**
        * Costante in millisecondi per ricalcolare la nuova posizione della mosca
        */
       
       private int sleep1=50;
       
       /**
        * Costante in millisecondi per calcolare la traiettoria della mosca
        */
       
       private int sleep2=500;

       /**
        * Angolo per girare il sistema assiale e quindi la mosca
        */
       
       private double angoloMosca;
       
       /**
        * Costruttore della classe. Inizializza le variabili principali e crea l'oggetto AffineTransform
        * @param _p Oggetto classe Primo
        */
       
       public Mosca(Primo _p) {
               p = _p;
               trasf = new AffineTransform();
               
               xA = 50;
               yA = 50;
               
               xPos = 100;
               yPos = 100;

               xDaRaggiungere=100;
               yDaRaggiungere=100;
               
               t = new Thread(this);
               t.start();
       }
       
       /**
        * Variazione x
        */
       
       double deltaX;
       
       /**
        * Variazione y
        */
       
       double deltaY;
       
       double retta;
       
       /**
        * Seno dell'angolo formato dalla traiettoria della mosca
        */
       
       double seno;
       
       /**
        * Coseno dell'angolo formato dalla traiettoria della mosca
        */
       
       double coseno;
       
       /**
        * Tangente dell'angolo formato dalla traiettoria della mosca
        */
       
       double tg;
       
       /**
        * Incremento lungo x
        */
       
       double incX ;
       
       /**
        * Incremento lungo y
        */
       
       double incY ;
       
       /**
        * Mantiene in esecuzione il thread e ricalcola in ogni istante la nuova posizione della mosca
        */

       
       public void run() {
               while(true) {
                       try {
                               t.sleep(sleep1);
                       }
                       catch(InterruptedException e) { System.out.println("Eccezzione: "+e); }

                       if( Math.abs(xDaRaggiungere - xPos) <= 10  && Math.abs(yDaRaggiungere -yPos) <= 10 ){ // se sono arrivato
                               try{
                                       t.sleep(sleep2);
                               }
                               catch(Exception e){}
                               
                               xDaRaggiungere = (int) Math.round(Math.random()*500) +100;
                               yDaRaggiungere = (int) Math.round(Math.random()*500) +100;
                               
                               deltaX = xDaRaggiungere - xPos;
                               deltaY = yDaRaggiungere - yPos;
                               
                               angoloMosca = Math.atan(deltaY/deltaX);
                       
                               retta = Math.sqrt(Math.pow(deltaX,2)+Math.pow(deltaY,2));
                               
                               seno = Math.abs(deltaY/retta);
                               coseno= Math.abs(deltaX/retta);
                               tg=seno/coseno;
                               
                               if(deltaX>deltaY){
                                       incX=2;
                                       incY=incX * tg;
                               }
                               else{
                                       incY=2;
                                       incX=incY / tg;
                               }                              
                               
                               if(deltaX>0 && deltaY>0){ // tutti +
                               }
                               else if(deltaX<0 && deltaY>0){
                                       incX=-incX;
                                       angoloMosca += Math.PI;
                               }
                               else if(deltaX<0 && deltaY<0){
                                       incX=-incX;
                                       incY=-incY;
                                       angoloMosca -= Math.PI;
                               }
                               else{ //deltaX>0 && deltaY<0
                                       incY= -incY;
                               }
                       }
                       
                       else{ // altrimenti vado dove devo
                           if(xPos+incX <600 && yPos+incY<600 && yPos+incY>0 && xPos+incX > 0){
                        	   xPos += incX;
                               yPos += incY;
                           }
                           else{
                        	   xPos=xDaRaggiungere;
                        	   yPos=yDaRaggiungere;
                           }
                       }
               }
       }
       
       /**
        * Ritorna la posizione lungo la coordinata x della mosca
        * @return La coordinata x
        */
       
       public double getX() {
               return xPos;
       }
       
       /**
        * Ritorna la posizione lungo la coordinata y della mosca
        * @return La coordinata y
        */
       
       public double getY() {
               return yPos;
       }
       
       /**
        * Disegna la mosca su un oggetto BufferedImage il quale andra' translato e ruotato rispetto al sistema rappresentato dall'oggetto trasf
        * @param g Oggetto Graphics sul quale disegnare l'immagine
        */
       
       public void disegna(Graphics g) {
               Graphics2D g2 = (Graphics2D) g;
               
               /* Creo un immagine con uno sfondo trasparente */
               BufferedImage buffer = new BufferedImage(100,100,BufferedImage.TYPE_INT_ARGB);
               
               /* Creo l'oggetto Graphics2D a partire dall'immagine */
               Graphics2D gbi = buffer.createGraphics();
               /* Imposto il rendering per l'immagine e il testo */
               gbi.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
               gbi.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
               
               /* Imposto il canale di trasparenza alpha (0 trasparente, 1 opaco) */
               float alfa = 0.9f; // trasparenza
               AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,alfa);
               gbi.setComposite(ac);
               
               
               //g.drawRect((int)xPos-100, (int)yPos, 100, 100);
               
               gbi.setPaint(Color.BLACK);
               /* Faccia */
               gbi.setPaint(new Color(102,201,229));
               gbi.fillOval(xA-10,yA-30,20,20);                
               gbi.setPaint(Color.BLACK);
               gbi.drawOval(xA-10,yA-30,20,20);
               
               /* Corpo */
               gbi.setPaint(Color.BLACK);
               gbi.fillOval(xA-10,yA-12,20,50);
               
               /* Ali */
               gbi.drawArc(xA-40, yA-8, 40, 60, 60,110);
               gbi.drawArc(xA-50, yA-40, 50, 60, 240,180);
               gbi.drawArc(xA, yA-8, 40, 60, 15,120);
               gbi.drawArc(xA, yA-40, 50, 60, -60,-190);


               /* Ruoto e translo il sistema */
               trasf.setToTranslation(xPos,yPos);
               trasf.rotate(angoloMosca + Math.PI/2);
               
               /* Disegno l'immagine sull'oggetto */
               g2.drawImage(buffer,trasf,p);
               g.setColor(Color.BLACK);
       }
}